package org.springblade.task.job.report.user;

import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.common.utils.DateUtils;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.modules.userAnalysis.entity.DailyRetainedUsersReport;
import org.springblade.modules.userAnalysis.service.IDailyRetainedUsersReportService;
import org.springblade.task.base.entity.BaseUser;
import org.springblade.task.base.param.BaseUserParam;
import org.springblade.task.base.service.IBaseUserService;
import org.springblade.task.base.service.IBaseUserVisitLogService;
import org.springblade.task.base.vo.BaseUserVO;
import org.springblade.task.job.base.BaseTaskInfoJob;
import org.springblade.task.quartz.entity.QuartzTask;
import org.springblade.task.quartz.service.IQuartzTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.*;

/**
 * @Title: 每日统计留存用户
 * @version V1.0
 */
@Component
public class DailyRetainedUsersReportJob {
	private static Logger logger = LoggerFactory.getLogger(BaseTaskInfoJob.class);

	@Autowired
	private IQuartzTaskService quartzTaskService;
	@Autowired
	private IBaseUserVisitLogService baseUserVisitLogService;
	@Autowired
	private IBaseUserService baseUserService;
	@Autowired
	private IDailyRetainedUsersReportService dailyRetainedUsersReportService;
	@Resource
	private BladeRedis bladeRedis;

	private static String LS_USER = "ls_user_";

	private static String TODAY_LOGIN_USER = "today_login_user_";

	/**
	 * 1、简单任务示例（Bean模式）
	 */
	@XxlJob("dailyRetainedUsersReportJob")
	public ReturnT<String> dailyRetainedUsersReportJob(String param) throws Exception {
		System.out.println(DateUtils.currentDateTime() + " -- XXL-JOB, Hello World.");
		System.err.println("执行静态定时任务日期: " + DailyRetainedUsersReportJob.class.getSimpleName());
		QuartzTask quartzTask = quartzTaskService.queryByTaskName(DailyRetainedUsersReportJob.class.getSimpleName(), -7);
		// 今日
		String todayDate = DateUtils.crutDate();
		String taskDate = quartzTask.getTaskDate();
		while (taskDate.compareTo(todayDate) < 0) {
			// 当时间大于5点，跳出执行
//			if (DateUtils.getHour24() > 5) {
//				break;
//			}
			// 再加一个凌晨1点判断
			currMethod(taskDate);
			// 增加1天
			taskDate = DateUtils.dateAddDay(taskDate, 1);
		}
		quartzTask.setTaskDate(taskDate);
		quartzTaskService.saveQuartzTask(quartzTask);
		return ReturnT.SUCCESS;
	}

	/**
	 *
	 * @param taskDate
	 */
	public void currMethod(String taskDate) {

		// 15日
		String startDate_15 = DateUtils.dateAddDay(taskDate, -15);
		// 30日
		String startDate_30 = DateUtils.dateAddDay(taskDate, -30);
		// 90日
		String startDate_90 = DateUtils.dateAddDay(taskDate, -90);

		// 前一日留存用户： 区间的前一天登录过，并且在区间内还有至少1次登录的用户计数
		// 时间区间：次日/7日/15日/30日/3个月
		// 次日
		List<String> quUserList = queryTimeIntervalUserList(taskDate, taskDate);
		bladeRedis.setEx(TODAY_LOGIN_USER + taskDate, quUserList,  Duration.ofDays(2));
		// 次日前一天
		String yesterday = DateUtils.dateAddDay(taskDate, -1);
		List<String> quBeforeDayUserList_1 = queryTimeIntervalUserList(yesterday, yesterday);
		List<BaseUserVO> firstLoginUserList_1 = queryFirstLoginUserList(yesterday);

		int retained_users_num = 0; // 次日留存用户数
		int retained_users_num_new = 0; // 次日留存新用户数
		int retained_users_num_old = 0; // 次日留存老用户数
		retainedUserNum(quUserList, quBeforeDayUserList_1, firstLoginUserList_1, retained_users_num, retained_users_num_new, retained_users_num_old);

		// 7日内有登陆记录的用户
		String startDate_7 = DateUtils.dateAddDay(taskDate, -7);
		List<String> quUserList_7 = queryTimeIntervalUserList(startDate_7, taskDate);
		// 7日前一天
		String startDate_8 = DateUtils.dateAddDay(startDate_7, -1);
		List<String> quUserList_8 = queryTimeIntervalUserList(startDate_8, startDate_8);
		List<BaseUserVO> firstLoginUserList_8 = queryFirstLoginUserList(startDate_8);

		int retained_users_num_7 = 0; // 次日留存用户数
		int retained_users_num_new_7 = 0; // 次日留存新用户数
		int retained_users_num_old_7 = 0; // 次日留存老用户数
		retainedUserNum(quUserList_7, quUserList_8, firstLoginUserList_8, retained_users_num_7, retained_users_num_new_7, retained_users_num_old_7);

		// 15日 内有登陆记录的用户
		List<String> quUserList_15 = queryTimeIntervalUserList(startDate_15, taskDate);
		// 15日前一天
		String startDate_16 = DateUtils.dateAddDay(startDate_15, -1);
		List<String> quUserList_16 = queryTimeIntervalUserList(startDate_16, startDate_16);
		List<BaseUserVO> firstLoginUserList_16 = queryFirstLoginUserList(startDate_16);

		int retained_users_num_15 = 0; // 次日留存用户数
		int retained_users_num_new_15 = 0; // 次日留存新用户数
		int retained_users_num_old_15 = 0; // 次日留存老用户数
		retainedUserNum(quUserList_15, quUserList_16, firstLoginUserList_16, retained_users_num_15, retained_users_num_new_15, retained_users_num_old_15);

		// 30日内有登陆记录的用户
		List<String> quUserList_30 = queryTimeIntervalUserList(startDate_30, taskDate);
		// 30日前一天
		String startDate_31 = DateUtils.dateAddDay(startDate_30, -1);
		List<String> quUserList_31 = queryTimeIntervalUserList(startDate_31, startDate_31);
		List<BaseUserVO> firstLoginUserList_31 = queryFirstLoginUserList(startDate_31);

		int retained_users_num_30 = 0; // 次日留存用户数
		int retained_users_num_new_30 = 0; // 次日留存新用户数
		int retained_users_num_old_30 = 0; // 次日留存老用户数
		retainedUserNum(quUserList_30, quUserList_31, firstLoginUserList_31, retained_users_num_30, retained_users_num_new_30, retained_users_num_old_30);

		// 90日内有登陆记录的用户
		List<String> quUserList_90 = queryTimeIntervalUserList(startDate_90, taskDate);
		// 15日前一天
		String startDate_91 = DateUtils.dateAddDay(startDate_90, -1);
		List<String> quUserList_91 = queryTimeIntervalUserList(startDate_91, startDate_91);
		List<BaseUserVO> firstLoginUserList_91 = queryFirstLoginUserList(startDate_91);

		int retained_users_num_90 = 0; // 次日留存用户数
		int retained_users_num_new_90 = 0; // 次日留存新用户数
		int retained_users_num_old_90 = 0; // 次日留存老用户数
		retainedUserNum(quUserList_90, quUserList_91, firstLoginUserList_91, retained_users_num_90, retained_users_num_new_90, retained_users_num_old_90);

		DailyRetainedUsersReport retainedUsersReport = new DailyRetainedUsersReport();
		retainedUsersReport.setDate(taskDate);
		retainedUsersReport.setType(1);
		retainedUsersReport.setSecondDay(retained_users_num);
		retainedUsersReport.setSevenDay(retained_users_num_7);
		retainedUsersReport.setFifteenDay(retained_users_num_15);
		retainedUsersReport.setThirtyDay(retained_users_num_30);
		retainedUsersReport.setNinetyDay(retained_users_num_90);

		DailyRetainedUsersReport retainedUsersReport_new = new DailyRetainedUsersReport();
		retainedUsersReport_new.setDate(taskDate);
		retainedUsersReport_new.setType(2);
		retainedUsersReport_new.setSevenDay(retained_users_num_new);
		retainedUsersReport_new.setSevenDay(retained_users_num_new_7);
		retainedUsersReport_new.setFifteenDay(retained_users_num_new_15);
		retainedUsersReport_new.setThirtyDay(retained_users_num_new_30);
		retainedUsersReport_new.setNinetyDay(retained_users_num_new_90);

		DailyRetainedUsersReport retainedUsersReport_old = new DailyRetainedUsersReport();
		retainedUsersReport_old.setDate(taskDate);
		retainedUsersReport_old.setType(3);
		retainedUsersReport_old.setSecondDay(retained_users_num_old);
		retainedUsersReport_old.setSevenDay(retained_users_num_old_7);
		retainedUsersReport_old.setFifteenDay(retained_users_num_old_15);
		retainedUsersReport_old.setThirtyDay(retained_users_num_old_30);
		retainedUsersReport_old.setNinetyDay(retained_users_num_old_90);

		// 前一日流失用户：区间内没有任何登录行为的用户计数
		// 时间区间：15日/30日/3个月
		int ls_user_num_15 = lessUserNum(startDate_15, quUserList_15);
		int ls_user_num_30 = lessUserNum(startDate_30, quUserList_30);
		int ls_user_num_90 = lessUserNum(startDate_90, quUserList_90);

		DailyRetainedUsersReport retainedUsersReport_ls = new DailyRetainedUsersReport();
		retainedUsersReport_ls.setDate(taskDate);
		retainedUsersReport_ls.setType(4);
		retainedUsersReport_ls.setSecondDay(0);
		retainedUsersReport_ls.setSevenDay(0);
		retainedUsersReport_ls.setFifteenDay(ls_user_num_15);
		retainedUsersReport_ls.setThirtyDay(ls_user_num_30);
		retainedUsersReport_ls.setNinetyDay(ls_user_num_90);
		// 前一日回流用户：区间内没有任何登录行为，但是之后又发生登录行为的用户计数
		// 时间区间：15日/30日/3个月
		int hl_user_num_15 = hlUserNum(taskDate, quUserList, -16);
		int hl_user_num_30 = hlUserNum(taskDate, quUserList, -31);
		int hl_user_num_90 = hlUserNum(taskDate, quUserList, -91);

		DailyRetainedUsersReport retainedUsersReport_hl = new DailyRetainedUsersReport();
		retainedUsersReport_hl.setDate(taskDate);
		retainedUsersReport_hl.setType(5);
		retainedUsersReport_hl.setSecondDay(0);
		retainedUsersReport_hl.setSevenDay(0);
		retainedUsersReport_hl.setFifteenDay(hl_user_num_15);
		retainedUsersReport_hl.setThirtyDay(hl_user_num_30);
		retainedUsersReport_hl.setNinetyDay(hl_user_num_90);

		List<DailyRetainedUsersReport> batchReport = new ArrayList<>();
		batchReport.add(retainedUsersReport);
		batchReport.add(retainedUsersReport_new);
		batchReport.add(retainedUsersReport_old);
		batchReport.add(retainedUsersReport_ls);
		batchReport.add(retainedUsersReport_hl);
		dailyRetainedUsersReportService.saveBatch(batchReport);
	}

	private int hlUserNum(String taskDate, List<String> quUserList, int amount) {
		int hu_user_num = 0;
		String hl_startDate = DateUtils.dateAddDay(taskDate, amount);
		Set<String> lsUserSet = bladeRedis.get(LS_USER + hl_startDate);
		if(lsUserSet != null) {
			for(String pin : quUserList) {
				if(lsUserSet.contains(pin)) {
					hu_user_num =+1;
				}
			}
		}
		return hu_user_num;
	}

	private int lessUserNum(String startDate, List<String> quUserList ) {
		int ls_user_num = 0;
		BaseUserParam loginParam = new BaseUserParam();
		loginParam.setFirstLoginTime(startDate);
		List<String> userList = baseUserService.queryLessThanFirstLoginTime(loginParam);
		Set<String> loginUserSet = new HashSet<>();
		Set<String> lsUserSet = new HashSet<>();
		for(String pin : quUserList) {
			loginUserSet.add(pin);
		}
		if(!CollectionUtils.isEmpty(userList)) {
			for(String pin : userList) {
				if(!loginUserSet.contains(pin)) {
					lsUserSet.add(pin);
				}
			}
			ls_user_num = userList.size() - (quUserList == null? 0 : quUserList.size());
		}

		bladeRedis.setEx(LS_USER + startDate, lsUserSet, Duration.ofDays(2));
		return ls_user_num;
	}

	/**
	 *
	 * @param quUserList
	 * @param quBeforeDayUserList
	 * @param firstLoginUserList
	 * @param retained_users_num
	 * @param retained_users_num_new
	 * @param retained_users_num_old
	 */
	private void retainedUserNum(List<String> quUserList, List<String> quBeforeDayUserList, List<BaseUserVO> firstLoginUserList,
		int retained_users_num, int retained_users_num_new, int retained_users_num_old) {
		Set<String> beforeDayUserSet = new HashSet<>();
		Set<String> retainedUserList = new HashSet<>(); // 次日留存用户
		for(String pin: quBeforeDayUserList) {
			beforeDayUserSet.add(pin);
		}
		for(String pin : quUserList) {
			if(beforeDayUserSet.contains(pin)) {
				retained_users_num = +1;
				retainedUserList.add(pin);
			}
		}
		for(BaseUserVO user: firstLoginUserList) {
			if(retainedUserList.contains(user.getPin())) {
				retained_users_num_new =+1;
			}
		}
		retained_users_num_old = retained_users_num = retained_users_num_new;
	}

	private List<BaseUserVO> queryFirstLoginUserList(String day) {
		BaseUserParam loginParam = new BaseUserParam();
		loginParam.setStartDate(DateUtils.getDateStartTime(day));
		loginParam.setEndDate(DateUtils.getDayEndTime(day));
		return baseUserService.queryTodayLoginUserList(loginParam);
	}

	private List<String> queryTimeIntervalUserList(String startDate, String endDate) {
		BaseUserParam ys_param = new BaseUserParam();
		ys_param.setStartDate(DateUtils.getDateStartTime(startDate));
		ys_param.setEndDate(DateUtils.getDayEndTime(endDate));
		 return baseUserVisitLogService.queryByTodayUserList(ys_param);
	}


	public void init() {
		logger.info("init");
	}

	public void destroy() {
		logger.info("destory");
	}

}
